package server.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.apache.commons.collections15.Transformer;

import server.Conversation;
import server.ServerMonitor;
import server.Session;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.DefaultVertexIconTransformer;
import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.decorators.VertexIconShapeTransformer;
import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;

/**
 * <h1>Class ConversationGraph</h1>
 * 
 * Displays a graph with the current users of the system and the conversations between
 * them.
 * 
 * @author Tomas
 * @date March 9 2009
 */
public class ConversationGraph {
	/**
     * Graph whose nodes represent the users in the system and whose edges conversations 
     * between them.
     */
    protected Graph<Integer,Number> graph;

    /**
     * Visual component and renderer for the graph
     */
    protected VisualizationViewer<Integer,Number> vv;
    
    protected ArrayList<String> usernames = null;
    
    protected boolean showLabels = true;
    
    @SuppressWarnings("unchecked")
	public ConversationGraph() {
        
    	usernames = new ArrayList<String>();
    	
        graph = new UndirectedSparseGraph<Integer,Number>();
        Integer[] v = createVertices();
        createEdges(v);
        
        vv =  new VisualizationViewer<Integer,Number>(new FRLayout<Integer,Number>(graph));
        vv.getRenderContext().setVertexLabelTransformer(new UnicodeVertexStringer<Integer>(v));
        vv.getRenderContext().setVertexLabelRenderer(new DefaultVertexLabelRenderer(Color.blue));
        vv.getRenderContext().setEdgeLabelRenderer(new DefaultEdgeLabelRenderer(Color.blue));
        VertexIconShapeTransformer<Integer> vertexIconShapeFunction =
            new VertexIconShapeTransformer<Integer>(new EllipseVertexShapeTransformer<Integer>());
        DefaultVertexIconTransformer<Integer> vertexIconFunction = new DefaultVertexIconTransformer<Integer>();
        vv.getRenderContext().setVertexShapeTransformer(vertexIconShapeFunction);
        vv.getRenderContext().setVertexIconTransformer(vertexIconFunction);
        loadImages(v, vertexIconFunction.getIconMap());
        vertexIconShapeFunction.setIconMap(vertexIconFunction.getIconMap());
        vv.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<Integer>(vv.getPickedVertexState(), Color.white,  Color.yellow));
        vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.lightGray));

        vv.setBackground(Color.white);

        // Add my listener for ToolTips
        vv.setVertexToolTipTransformer(new ToStringLabeller<Integer>());
        
        // Create a frame to hold the graph
        final JFrame frame = new JFrame();
        frame.setTitle("Parlanchin - Conversation graph");
        Container content = frame.getContentPane();
        final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
        content.add(panel);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        final ModalGraphMouse gm = new DefaultModalGraphMouse<Integer,Number>();
        vv.setGraphMouse(gm);
        
        final ScalingControl scaler = new CrossoverScalingControl();

        JButton plus = new JButton("+");
        plus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1.1f, vv.getCenter());
            }
        });
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1/1.1f, vv.getCenter());
            }
        });

        JCheckBox lo = new JCheckBox("Show Labels");
        lo.addItemListener(new ItemListener(){
            public void itemStateChanged(ItemEvent e) {
                showLabels = e.getStateChange() == ItemEvent.SELECTED;
                vv.repaint();
            }
        });
        lo.setSelected(true);
        
        JPanel controls = new JPanel();
        controls.add(plus);
        controls.add(minus);
        controls.add(lo);
        controls.add(((DefaultModalGraphMouse<Integer,Number>) gm).getModeComboBox());
        content.add(controls, BorderLayout.SOUTH);

        frame.pack();
        frame.setLocationRelativeTo(null);
        
        frame.setVisible(true);
    }
    
    
    class UnicodeVertexStringer<V> implements Transformer<V,String> {

        Map<V,String> map = new HashMap<V,String>();
        Map<V,Icon> iconMap = new HashMap<V,Icon>();
        
        public UnicodeVertexStringer(V[] vertices) {
            for(int i=0; i<vertices.length; i++) {
                map.put(vertices[i], usernames.get(i));
            }
        }
        
        /**
         * @see edu.uci.ics.jung.graph.decorators.VertexStringer#getLabel(edu.uci.ics.jung.graph.Vertex)
         */
        public String getLabel(V v) {
            if(showLabels) {
                return (String)map.get(v);
            } else {
                return "";
            }
        }
        
		public String transform(V input) {
			return getLabel(input);
		}
    }
    
    /**
     * Create one vertex per online user.
     * 
     * @return
     * 		Vertex in the array.
     */
    private Integer[] createVertices() {
        
        Iterator<String> it = ServerMonitor.getInstance().getUsersOnline();
        while(it.hasNext()){
        	String name = it.next();
        	usernames.add(name);
        }
        
        Integer[] v = new Integer[usernames.size()];
        
        for(int i = 0; i < usernames.size(); i++){
        	v[i] = new Integer(i);
        	graph.addVertex(v[i]);
        }
        
        return v;
    }

    /**
     * Create an edge per conversation.
     * 
     * @param v
     * 		Vertex array to be linked.
     */
    void createEdges(Integer[] v) {

    	ServerMonitor server = ServerMonitor.getInstance();
    	
        Iterator<String> it = server.getConversationsIDs();
        
        while(it.hasNext()){
        	String convID = it.next();
        	Conversation conv = server.getConversation(convID);
        	Iterator<Session> ses = conv.getParticipants();
        	ArrayList<String> participants = new ArrayList<String>();
        	while(ses.hasNext()){
        		participants.add(ses.next().getOwner().getUsername());
        	}
        	
        	for(int i = 0; i < participants.size(); i++){
        		int p1 = usernames.indexOf(participants.get(i));
        		for(int j = i+1; j < participants.size(); j++){
        			int p2 = usernames.indexOf(participants.get(j));
        			try{
        				graph.addEdge(new Double(Math.random()), v[p1], v[p2], EdgeType.UNDIRECTED);
        			}catch(Exception e){
        				
        			}
        		}
        	}
        }
        
    	
    }

    /**
     * Loads the images for the nodes.
     */
    protected void loadImages(Integer[] vertices, Map<Integer,Icon> imageMap) {
        
        ImageIcon icon = new ImageIcon("./serverImages/buddy.png");
        
        for(int i=0; icon != null && i<vertices.length; i++) {
            imageMap.put(vertices[i],icon);
        }
    }
    
}
